#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>

#define CHARDEVBASE_MAJOR    200 // 主设备号
#define CHARDEVBASE_NAME      "chardev" // 设备名

static char readbuf[100];
static char writebuf[100];
static const char kerneldata[] = "kernal data";

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件，file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */

static int chardevbase_open(struct inode * inode, struct file *fp)
{
    printk("openfile");
    return 0;
}

 /*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数，如果为负值，表示读取失败
 */

static ssize_t chardevbase_read(struct file * fp, char __user *buf, size_t count, loff_t *off_t)
{
    //模拟向用户发数据
    memcpy(readbuf, kerneldata, sizeof(kerneldata));
    int retvalue;
    retvalue = copy_to_user(buf, readbuf, count);
    if (retvalue >= 0)
        printk("kernel senddata sucess \n\r");
    else
        printk("kernel senddata faild \n\r");
     return retvalue;

}

/*
 * @description		: 向设备写数据 
 * @param - filp 	: 设备文件，表示打开的文件描述符
 * @param - buf 	: 要写给设备写入的数据
 * @param - cnt 	: 要写入的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 写入的字节数，如果为负值，表示写入失败
 */

static ssize_t chardevbase_write(struct file * fp, const char __user *buf, size_t cnt, loff_t * offt)
{
    int retvalue;
    retvalue =  copy_from_user(writebuf, buf, cnt);
    if (retvalue >= 0)
        printk("kener receive sucess \n\r");
    else
        printk("kernel receive faild \n\r");
    
    return retvalue;
}

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */

static int chardevbase_release(struct inode *inode, struct file * fp)
{
    printk("close file");
    return 0;
}

/*
 * 设备操作函数结构体
 */

static struct file_operations chardevbase_op = {
    .owner = THIS_MODULE,
    .open  = chardevbase_open,
    .read  = chardevbase_read,
    .write = chardevbase_write,
    .release = chardevbase_release
};

/*
 * @description	: 驱动入口函数 
 * @param 		: 无
 * @return 		: 0 成功;其他 失败
 */
static int __init chardevbase_init(void)
{   int retvalue;
    retvalue = register_chrdev(CHARDEVBASE_MAJOR, CHARDEVBASE_NAME, &chardevbase_op);
    if (retvalue >=  0)
        printk("init sucess \n\r");
    else
        printk("init faild\n\r");
    return retvalue;
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __exit chardevbase_exit(void)
{
    unregister_chrdev(CHARDEVBASE_MAJOR, CHARDEVBASE_NAME);
    printk("unregist sucess\n\r");
    return 0;
}


module_init(chardevbase_init);
module_exit(chardevbase_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("shiyue");






